package exercise.jslide.jslide.model.shapes;

import exercise.jslide.jslide.utils.EdgePoint;
import exercise.jslide.jslide.utils.SerializableColor;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.geometry.Point2D;
import exercise.jslide.jslide.model.SlideElement;

public abstract class Shape extends SlideElement {
    protected double strokeWidth;//边的宽度
    protected boolean isSelected;//是否被选中（与鼠标事件联动）
    public EdgePoint getEdgePoint() {
        return edgePoint;
    }

    private EdgePoint edgePoint;

    public Shape() {
        this.fillColor = new SerializableColor(Color.WHITE); // 默认填充色为白色
        this.strokeColor = new SerializableColor(Color.BLACK); // 默认边界色为黑色
        this.strokeWidth = 1.0; // 默认边界宽度为1
    }

    @Override
    public void draw(GraphicsContext gc) {
        gc.save(); // 保存当前画布状态
        gc.setFill(fillColor.getFXColor()); // 设置填充色
        gc.setStroke(strokeColor.getFXColor()); // 设置边界色
        gc.setLineWidth(strokeWidth); // 设置边界宽度

        // 具体的绘制由子类实现
        drawShape(gc);

        // 如果被选中，绘制选择框和控制点
        if (isSelected) {
            drawSelectionFrame(gc);
            drawControlPoints(gc);
        }

        gc.restore();
    }

    protected abstract void drawShape(GraphicsContext gc);

    //以下函数式用来绘制点击后的框
    protected void drawSelectionFrame(GraphicsContext gc) {
        gc.setStroke(Color.BLUE); // 设置选择框颜色为蓝色
        gc.setLineDashes(3); // 设置虚线
        gc.strokeRect(x - 2, y - 2, width + 4, height + 4); // 绘制虚线框
        gc.setLineDashes(null); // 取消虚线
    }

    protected void drawControlPoints(GraphicsContext gc) {
        final double SIZE = 4; // 控制点大小
        gc.setFill(Color.WHITE); // 控制点填充色
        gc.setStroke(Color.BLUE); // 控制点边界色

        // 8个控制点的位置
        Point2D[] points = {
                new Point2D(x, y),                    // 左上
                new Point2D(x + width/2, y),          // 上中
                new Point2D(x + width, y),            // 右上
                new Point2D(x + width, y + height/2), // 右中
                new Point2D(x + width, y + height),   // 右下
                new Point2D(x + width/2, y + height), // 下中
                new Point2D(x, y + height),           // 左下
                new Point2D(x, y + height/2)          // 左中
        };

        for (Point2D p : points) {
            gc.fillRect(p.getX() - SIZE/2, p.getY() - SIZE/2, SIZE, SIZE);
            gc.strokeRect(p.getX() - SIZE/2, p.getY() - SIZE/2, SIZE, SIZE);
        }
    }

    public void setEdgePoint(Point2D point){
        if(point.getX()>x+width-3 && point.getX()<=x+width+3 && point.getY()>y+height/2-3 && point.getY()<=y+height/2+3){
            edgePoint = EdgePoint.RightMid;
        }
        else if(point.getX()<x+3 && point.getX()>=x-3 && point.getY()>y+height/2-3 && point.getY()<=y+height/2+3){
            edgePoint = EdgePoint.LeftMid;
        }
        else if(point.getY()>y+height-3 && point.getY()<=y+height+3 && point.getX()>x+width/2-3 && point.getX()<=x+width/2+3){
            edgePoint = EdgePoint.MidDown;
        }
        else if(point.getY()<y+3 && point.getY()>=y-3 && point.getX()>x+width/2-3 && point.getX()<=x+width/2+3){
            edgePoint = EdgePoint.MidUp;
        } else if (point.getX()<x+3 && point.getX()>=x-3 && point.getY()<y+3 && point.getY()>=y-3) {
            edgePoint = EdgePoint.LeftUp;
        }
        else if(point.getX()>x+width-3 && point.getX()<=x+width+3 && point.getY()<y+3 && point.getY()>=y-3){
            edgePoint = EdgePoint.RightUP;
        }
        else if(point.getX()<x+3 && point.getX()>=x-3 && point.getY()>y+height-3 && point.getY()<=y+height+3){
            edgePoint = EdgePoint.LeftDown;
        }
        else if(point.getX()>x+width-3 && point.getX()<=x+width+3 && point.getY()>y+height-3 && point.getY()<=y+height+3){
            edgePoint = EdgePoint.RightDown;
        }
        else {
            edgePoint = EdgePoint.noPoint;
        }
//        System.out.println(edgePoint);
    }

    public void reSize(double deltaX,double deltaY){
        if(edgePoint == EdgePoint.noPoint){

        }
        if(edgePoint == EdgePoint.MidDown){
            height = height+deltaY;
        }
        if(edgePoint == EdgePoint.MidUp){
            y = y+deltaY;
            height = height-deltaY;
        }
        if(edgePoint == EdgePoint.LeftMid){
            x = x+deltaX;
            width = width-deltaX;
        }
        if(edgePoint == EdgePoint.RightMid){
            width = width+deltaX;
        }
        if(edgePoint == EdgePoint.LeftUp){
            x = x+deltaX;
            width = width-deltaX;
            y = y+deltaY;
            height = height-deltaY;
        }
        if(edgePoint == EdgePoint.LeftDown){
            height = height+deltaY;
            x = x+deltaX;
            width = width-deltaX;
        }
        if(edgePoint == EdgePoint.RightDown){
            height = height+deltaY;
            width = width+deltaX;
        }
        if(edgePoint == EdgePoint.RightUP){
            y = y+deltaY;
            height = height-deltaY;
            width = width+deltaX;
        }

    }

    public void setFillColor(SerializableColor color) {
        this.fillColor = color;
    }

    public void setStrokeColor(SerializableColor color) {
        this.strokeColor = color;
    }

    public void setStrokeWidth(double width) {
        this.strokeWidth = width;
    }

    public enum ShapeStyle {
        DEFAULT, OUTLINED, FILLED, DASHED
    }

    public void applyStyle(ShapeStyle style) {
        switch(style) {
            case OUTLINED:
                fillColor= new SerializableColor(Color.TRANSPARENT);
                break;
            // ...
        }
    }
}
